package com.svconnect.services;

import java.io.File;
import java.io.FileNotFoundException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.svconnect.exceptions.BindingNotFoundException;
import com.svconnect.model.config.BindingType;
import com.svconnect.model.config.Endpoint;
import com.svconnect.util.Log;

public class WebConfig {
	
	public synchronized static void setPath(String path) {
		WebConfigHolder.instance = new WebConfig(path);
	}
	
	private static class WebConfigHolder {
		private static WebConfig instance = new WebConfig("Web.config");
	}
	
	public synchronized static WebConfig getInstance() {
		return WebConfigHolder.instance;
	}
	
	private String path;
	private Document document;
	
	private WebConfig(String path) {
		this.path = path;
	}
	
	private void load() throws FileNotFoundException {
		File conf = new File(path);
		if (conf.exists()) {
			try {
				DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
				domFactory.setNamespaceAware(true);
				DocumentBuilder builder = domFactory.newDocumentBuilder();
				document = builder.parse(path);
			}
			catch(Exception ex) {
				Log.e(ex);
			}
		}
		else
			throw new FileNotFoundException(path);
	}
	
	public synchronized Endpoint getBinding(String contractName) throws BindingNotFoundException {
		if (document==null)  {
			try {
				this.load();
				
			} catch (Exception e) {
				File f = new File(this.path);
				throw new BindingNotFoundException(contractName,f);
			}
		}

		try {
			Element endpointEl = this.getElementByAttribute(document,"endpoint", "contract", contractName);
			String bindingTypeName = getNodeAttribute(endpointEl,"binding");
			String address = getNodeAttribute(endpointEl,"address");
			String bindingName = getNodeAttribute(endpointEl, "name");
			
			Endpoint endpoint = new Endpoint();
			endpoint.setName(bindingName);
			endpoint.setBinding(getBindingType(bindingTypeName));
			endpoint.setAddress(address);
	
			// TODO: get binding configuration
			
			return endpoint;

		} catch (Exception e) {
			throw new BindingNotFoundException(contractName);
		}
	}
	
	private BindingType getBindingType(String bindingTypeName) {
		switch(bindingTypeName) {
			case "basicHttpBinding":
				return BindingType.BasicHttpBinding;
			case "wsHttpBinding":
				return BindingType.WSHttpBinding;
		}
		return null;
	}
	
	private Element getElementByAttribute(Document doc, String tagName,
			String attrName, String attrValue) {
		NodeList bindings = doc.getElementsByTagName(tagName);
		for (int i = 0; i < bindings.getLength(); i++) {
			Element bnd = (Element) bindings.item(i);
			String attr = this.getNodeAttribute(bnd, attrName);
			if (attr != null && attr.equals(attrValue)) {
				return bnd;
			}
		}
		return null;
	}
	
	private String getNodeAttribute(Node node, String attrName) {
		Attr nameAttr = (Attr) node.getAttributes().getNamedItem(attrName);
		return (nameAttr != null) ? nameAttr.getValue() : null;
	}	
}
